#include "OpenGLWidgetCtl.h"
#include<QDebug>

#include<gl/GLU.h>


 void OpenGLWidgetCtl::TestMaxGLBufferData()
{
	//glewInit();

#ifdef _WIN64
	printf("WIN64 mode: \n");
#else
	printf("WIN32 mode: \n");
#endif

	long long nNumberM = 0;
	// 限制一个数目，防止程序异常不能跳出(联想 T530 ) [12/2/2016 ZOSH];
	const long long MAX_NUMBER = 10000;
	while (glGetError() == GL_NO_ERROR && nNumberM < MAX_NUMBER)
	{
		GLuint objectVBO = 0;
		glGenBuffers(1, &objectVBO);
		glBindBuffer(GL_ARRAY_BUFFER, objectVBO);
		// 1<<20 = 1M 的空间;
		glBufferData(GL_ARRAY_BUFFER, 1 << 20, NULL, GL_STATIC_DRAW);
		nNumberM++;
	}

	printf("gpu  max size: %lld M,  (x, y, z):%lld \n", nNumberM, nNumberM * 1024 * (1024 / 12));
	printf("test end!!!\n");
}




static unsigned int VBO, VAO;
static unsigned int shaderProgram;
static unsigned int EBO;

static float vertices[] = {
	0.5f, 0.5f, 0.0f,  // top right
	0.5f,-0.5f, 0.0f, // bottom right
	-0.5f, -0.5f, 0.0f, // bottom left
	-0.5f, 0.5f, 0.0f // top left
};

static unsigned int indices[] = {
	0,1,3, // first triangle
	1,2,3 // second triangle 

};


static const char* vertexShaderSource = R"(
#version 330 core
layout(location=0) in vec3 aPos;
void main()
{
	gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}
)";

static const char* fragmentShaderSource = R"(
out vec4 FragColor;
void main()
{
	FragColor = vec4(1.0f, 0.5f, 0.3f, 1.0f);
}
)";

OpenGLWidgetCtl::OpenGLWidgetCtl(QWidget* parent) :QOpenGLWidget(parent)
{}

OpenGLWidgetCtl::~OpenGLWidgetCtl()
{
	makeCurrent();
	glDeleteBuffers(1, &VBO);
	glDeleteVertexArrays(1, &VAO);
	glDeleteProgram(shaderProgram);
	doneCurrent();
}

void OpenGLWidgetCtl::drawShape(Shape shape)
{
	_shape = shape;
	update();
}

void OpenGLWidgetCtl::setWireFrame(bool wireFrame)
{
	// 在paintGL 函数以外的地方调用OpenGL函数没有意义，最终会被paintGL覆盖。所以必须以如下方式调用OpenGL函数。
	makeCurrent(); // --- 外部调用OpenGL函数前必须以 makeCurrent 函数开始
	if (wireFrame)
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	}
	else
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	}
	update();     // --- 外部调用OpenGL函数之后必须以 update 函数更新UI界面
	doneCurrent();// --- 外部调用OpenGL函数之后必须以 doneCurrent 函数结束
	//this->se
}

void OpenGLWidgetCtl::initializeGL()
{
	initializeOpenGLFunctions(); // 初始化opengl 相关的函数
								 // 创建vao vbo 对象 ，并赋予ID

	//TestMaxGLBufferData();

	glGenVertexArrays(1, &VAO);
	glGenBuffers(1, &VBO);

	// 创建VBO VAO 对象
	glBindVertexArray(VAO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	// 为当前绑定到target 的缓冲区对象创建一个新的数据存储。
	// 如果data 不是NULL，则使用来自此指针的数据初始化数据存储
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	// 创建EBO对象
	glGenBuffers(1, &EBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
	//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

	// 告知显卡如何解析缓冲区里的属性值
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);

	// 开启VAO 管理的第一个属性值
	glEnableVertexAttribArray(0);
	glBindBuffer(GL_ARRAY_BUFFER, 0);

	glBindVertexArray(0);


	// build and compile our shader program
	// 顶点着色器
	unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
	glCompileShader(vertexShader);

	//check for shader compile errors
	int success; char infoLog[512];
	glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
	if (!success)
	{
		glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
		qDebug() << "error::shader::vertex::compileation_failed  " << infoLog;
	}
	// 片段着色器
	unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
	glCompileShader(fragmentShader);
	glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
	if (!success)
	{
		glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
		qDebug() << "error::shader::fragment::compileation_failed " << infoLog;
	}

	// link shaders
	shaderProgram = glCreateProgram();
	glAttachShader(shaderProgram, vertexShader);
	glAttachShader(shaderProgram, fragmentShader);
	glLinkProgram(shaderProgram);
	// check for linking errors
	glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
	if (!success)
	{
		glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
		qDebug() << "error::shader::programe::linking_failed " << infoLog;
	}

	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);
}

void OpenGLWidgetCtl::resizeGL(int w, int h)
{
}

void OpenGLWidgetCtl::paintGL()
{
	glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT);

	qDebug() << "paintGL";

	glUseProgram(shaderProgram);

	glBindVertexArray(VAO);

	switch (_shape)
	{
	case Shape::Rect:
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
	default:
		break;
	}
	

	// 在传入 &indices 之前必须使用如下glBindBuffer 函数
	//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
	//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, &indices);
}
